﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.Configuration;
using System.Text.RegularExpressions;

namespace BarCodeLibrary {

    /// <summary>
    /// Code39：生成39條碼。
    /// </summary>
    public class Code39 {
        //對應碼表
        private Hashtable Decode;
        
        private Hashtable CheckCode;
        //每個字元間的間隔符
        private string SPARATOR = "0";
        public int WidthCU = 3;  //粗線和寬間隙寬度
        public int WidthXI = 1;  //細線和窄間隙寬度
        public int xCoordinate = 10;//75;  //條碼起始座標
        public int LineHeight = 60;
        private int Height = 0;
        private int Width = 0;

        public Code39() {
            Decode = new Hashtable();
            Decode.Add("0", "000110100");
            Decode.Add("1", "100100001");
            Decode.Add("2", "001100001");
            Decode.Add("3", "101100000");
            Decode.Add("4", "000110001");
            Decode.Add("5", "100110000");
            Decode.Add("6", "001110000");
            Decode.Add("7", "000100101");
            Decode.Add("8", "100100100");
            Decode.Add("9", "001100100");
            Decode.Add("A", "100001001");
            Decode.Add("B", "001001001");
            Decode.Add("C", "101001000");
            Decode.Add("D", "000011001");
            Decode.Add("E", "100011000");
            Decode.Add("F", "001011000");
            Decode.Add("G", "000001101");
            Decode.Add("H", "100001100");
            Decode.Add("I", "001001101");
            Decode.Add("J", "000011100");
            Decode.Add("K", "100000011");
            Decode.Add("L", "001000011");
            Decode.Add("M", "101000010");
            Decode.Add("N", "000010011");
            Decode.Add("O", "100010010");
            Decode.Add("P", "001010010");
            Decode.Add("Q", "000000111");
            Decode.Add("R", "100000110");
            Decode.Add("S", "001000110");
            Decode.Add("T", "000010110");
            Decode.Add("U", "110000001");
            Decode.Add("V", "011000001");
            Decode.Add("W", "111000000");
            Decode.Add("X", "010010001");
            Decode.Add("Y", "110010000");
            Decode.Add("Z", "011010000");
            Decode.Add("-", "010000101");
            Decode.Add("%", "000101010");
            Decode.Add("$", "010101000");
            Decode.Add("*", "010010100");

            CheckCode = new Hashtable();
            CheckCode.Add("0", "0");
            CheckCode.Add("1", "1");
            CheckCode.Add("2", "2");
            CheckCode.Add("3", "3");
            CheckCode.Add("4", "4");
            CheckCode.Add("5", "5");
            CheckCode.Add("6", "6");
            CheckCode.Add("7", "7");
            CheckCode.Add("8", "8");
            CheckCode.Add("9", "9");
            CheckCode.Add("A", "10");
            CheckCode.Add("B", "11");
            CheckCode.Add("C", "12");
            CheckCode.Add("D", "13");
            CheckCode.Add("E", "14");
            CheckCode.Add("F", "15");
            CheckCode.Add("G", "16");
            CheckCode.Add("H", "17");
            CheckCode.Add("I", "18");
            CheckCode.Add("J", "19");
            CheckCode.Add("K", "20");
            CheckCode.Add("L", "21");
            CheckCode.Add("M", "22");
            CheckCode.Add("N", "23");
            CheckCode.Add("O", "24");
            CheckCode.Add("P", "25");
            CheckCode.Add("Q", "26");
            CheckCode.Add("R", "27");
            CheckCode.Add("S", "28");
            CheckCode.Add("T", "29");
            CheckCode.Add("U", "30");
            CheckCode.Add("V", "31");
            CheckCode.Add("W", "32");
            CheckCode.Add("X", "33");
            CheckCode.Add("Y", "34");
            CheckCode.Add("Z", "35");
            CheckCode.Add("-", "36");
            CheckCode.Add(".", "37");
            CheckCode.Add(",", "38");
            CheckCode.Add("$", "39");
            CheckCode.Add("/", "40");
            CheckCode.Add("+", "41");
            CheckCode.Add("%", "42");
        }
        //保存檔
        public Boolean saveFile(string Code, string Title, int UseCheck, int ValidateCode) {
            //string code39 = Encode39(Code, UseCheck, ValidateCode);
            //if (code39 != null) {
            //    Bitmap saved = new Bitmap(this.Width, this.Height);
            //    Graphics g = Graphics.FromImage(saved);
            //    g.FillRectangle(new SolidBrush(Color.White), 0, 0, this.Width, this.Height);
            //    this.DrawBarCode39(code39, Title, g);
            //    //string path = ConfigurationSettings.AppSettings["ImagePath"];
            //    string path = string.Empty;
            //    SaveFileDialog saveFile = new SaveFileDialog();
            //    saveFile.Filter = "*.JPEG|*.JPEG|*.JPG|*.JPG";
            //    saveFile.ShowDialog();
            //    if (!saveFile.FileName.Equals("")) {
            //        path = saveFile.FileName;
            //    }
            //    else {
            //        return false;
            //    }
            //    string filename = path + Code + ".jpg";
            //    saved.Save(filename, ImageFormat.Jpeg);
            //    saved.Dispose();
            //    return true;
            //}
            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Code">要生成條碼的內容</param>
        /// <param name="Title">要顯示的標題</param>
        /// <param name="UseCheck">計算檢查碼</param>
        /// <returns></returns>
        public Bitmap CreateBarCode(string Code, string Title, int UseCheck, int ValidateCode) {
            string code39 = Encode39(Code, UseCheck, ValidateCode);
            if (code39 != null) {
                Bitmap saved = new Bitmap(this.Width, this.Height);
                Graphics g = Graphics.FromImage(saved);
                g.FillRectangle(new SolidBrush(Color.White), 0, 0, this.Width, this.Height);
                this.DrawBarCode39(code39, Title, g);
                return saved;
            }
            return null;
        }
        /***
        * Code:未經編碼的字串
        * 
        * **/
        private string Encode39(string Code, int UseCheck, int ValidateCode) {
            int UseStand = 1;  //檢查輸入待編碼字元是否為標準格式（是否以*開始結束）

            //保存備份資料
            string originalCode = Code;

            //為空不進行編碼
            if (null == Code || Code.Trim().Equals("")) {
                return null;
            }
            //檢查錯誤字元
            Code = Code.ToUpper();  //轉為大寫
            Regex rule = new Regex(@"[^0-9A-Z%$\-*]");
            if (rule.IsMatch(Code)) {
              //  MessageBox.Show("編碼中包含非法字元，目前僅支援字母,數位及%$-*符號!!");
                return null;
            }
            //計算檢查碼
            if (UseCheck == 1) {
                int Check = 0;
                //累計求和
                for (int i = 0; i < Code.Length; i++) {
                    Check += int.Parse((string)CheckCode[Code.Substring(i, 1)]);
                }
                //取模
                Check = Check % 43;
                //附加檢測碼
                if (ValidateCode == 1) {
                    foreach (DictionaryEntry de in CheckCode) {
                        if ((string)de.Value == Check.ToString()) {
                            Code = Code + (string)de.Key;
                            break;
                        }
                    }
                }
            }
            //標準化輸入字元，增加起始標記
            if (UseStand == 1) {
                if (Code.Substring(0, 1) != "*") {
                    Code = "*" + Code;
                }
                if (Code.Substring(Code.Length - 1, 1) != "*") {
                    Code = Code + "*";
                }
            }
            //轉換成39編碼
            string Code39 = string.Empty;
            for (int i = 0; i < Code.Length; i++) {
                Code39 = Code39 + (string)Decode[Code.Substring(i, 1)] +SPARATOR;
            }

            int height = 30 + LineHeight;//定義圖片高度      
            int width = xCoordinate;
            for (int i = 0; i < Code39.Length; i++) {
                if ("0".Equals(Code39.Substring(i, 1))) {
                    width += WidthXI;
                }
                else {
                    width += WidthCU;
                }
            }
            this.Width = width + xCoordinate;
            this.Height = height;

            return Code39;
        }

        private void DrawBarCode39(string Code39, string Title, Graphics g) {
            int UseTitle = 1;  //條碼上端顯示標題
            //int UseTTF = 1;  //使用TTF字體，方便顯示中文，需要$UseTitle=1時才能生效
            if (Title.Trim().Equals("")) {
                UseTitle = 0;
            }
            Pen pWhite = new Pen(Color.White, 1);
            Pen pBlack = new Pen(Color.Black, 1);
            int position = xCoordinate;
            //顯示標題
            if (UseTitle == 1) {
                Font TitleFont = new Font("宋體", 16, FontStyle.Bold);
                SizeF sf = g.MeasureString(Title, TitleFont);
                g.DrawString(Title, TitleFont, Brushes.Black, (Width - sf.Width) / 2, 5);
            }
            for (int i = 0; i < Code39.Length; i++) {
                //繪製條線
                if ("0".Equals(Code39.Substring(i, 1))) {
                    for (int j = 0; j < WidthXI; j++) {
                        g.DrawLine(pBlack, position + j, 30, position + j, 30 + LineHeight);
                    }
                    position += WidthXI;
                }
                else {
                    for (int j = 0; j < WidthCU; j++) {
                        g.DrawLine(pBlack, position + j, 30, position + j, 30 + LineHeight);
                    }
                    position += WidthCU;
                }
                i++;
                //繪製間隔線
                if ("0".Equals(Code39.Substring(i, 1))) {
                    position += WidthXI;
                }
                else {
                    position += WidthCU;
                }
            }
            return;
        }

    }
}


